Skip to content

Don't show skeleton on SSR!#1193

Merged
skyfallwastaken merged 6 commits intomainfrom
ssr-deferred
Apr 20, 2026
Merged

Don't show skeleton on SSR!#1193
skyfallwastaken merged 6 commits intomainfrom
ssr-deferred

Conversation

@skyfallwastaken
Copy link
Copy Markdown
Member

No description provided.

Copilot AI review requested due to automatic review settings April 19, 2026 12:48
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 19, 2026

Greptile Summary

This PR fixes a flash of skeleton UI during SSR by (1) calling setPage(page) synchronously in App.svelte before the first render so the global page store is populated server-side, and (2) short-circuiting the <Deferred> skeleton in SignedIn.svelte when dashboard_stats is already present in props.

  • P1 – reloading opacity lost: Users who land via SSR (the new common path) will never see the opacity-60 loading overlay when changing dashboard filters, because the {#if dashboard_stats} branch has no access to <Deferred>'s reloading state.
  • P2 – duplication: The dashboard markup (TodaySentence, Dashboard, ActivityGraph) is now copy-pasted across both branches; a shared Svelte snippet would eliminate this.

Confidence Score: 4/5

Safe to merge for the skeleton fix, but the reloading opacity regression should be addressed before landing.

The vendor/ change is correct and focused. The SignedIn.svelte change achieves its goal (no skeleton flash on SSR) but introduces a P1 UX regression: filter-change reloads no longer show any visual feedback for the majority of users who arrive via SSR.

app/javascript/pages/Home/SignedIn.svelte — the reloading overlay logic needs to be preserved or re-implemented for the SSR render path.

Important Files Changed

Filename Overview
app/javascript/pages/Home/SignedIn.svelte Adds an SSR-first render path that bypasses the Deferred skeleton, but the reloading opacity indicator is lost for SSR-served users who change filters, and the dashboard markup is now duplicated in two branches.
vendor/inertia/packages/svelte/dist/components/App.svelte Adds a synchronous setPage(page) call before the initial render so the global page store is populated during SSR; the existing $effect.pre still handles subsequent reactive updates on the client.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Page Request] --> B{SSR?}
    B -- Yes --> C[App.svelte: setPage sync]
    C --> D{dashboard_stats in props?}
    B -- No / Client Nav --> D
    D -- Yes --> E[Render dashboard content directly\nno skeleton, no reloading overlay]
    D -- No --> F[Render Deferred component]
    F --> G{Data loaded?}
    G -- No --> H[Show Skeleton fallback]
    G -- Yes --> I[Render dashboard content\nwith reloading opacity support]
    E --> J[User changes filters]
    J --> K[refreshDashboardData via router.visit]
    K --> L[dashboard_stats updated\nbut NO loading indicator shown]
    I --> J
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: app/javascript/pages/Home/SignedIn.svelte
Line: 136-209

Comment:
**Reloading opacity lost in SSR branch**

When `dashboard_stats` is already populated on SSR/hydration the component permanently stays in the `{#if dashboard_stats}` branch. That branch has no `reloading` indicator, so when `refreshDashboardData` triggers a partial Inertia visit (`only: ["dashboard_stats"]`), the old data stays visible with zero visual feedback — the `class:opacity-60={reloading}` that was in the `<Deferred>` children snippet is effectively unreachable for any user who arrives via SSR (which is the common path after this change).

Consider forwarding the `reloading` state from the `<Deferred>` snippet into a shared variable, or wrapping the SSR branch in the same `<Deferred>` and skipping the fallback skeleton conditionally.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: app/javascript/pages/Home/SignedIn.svelte
Line: 136-166

Comment:
**Duplicated dashboard rendering logic**

The `TodaySentence`, `Dashboard`, and `ActivityGraph` rendering is now copy-pasted verbatim between lines 137–166 (SSR branch) and lines 179–207 (Deferred children snippet). Per the project style guide, duplicated markup like this should be extracted into a shared Svelte snippet or child component. A simple `{#snippet dashboardContent(reloading)}` declared once above the `{#if}` block would eliminate both copies and make the `reloading` opacity easy to restore.

**Context Used:** In the Hackatime repo, please ensure that the PR i... ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Don't show skeleton on SSR!" | Re-trigger Greptile

Comment thread app/javascript/pages/Home/SignedIn.svelte Outdated
Comment thread app/javascript/pages/Home/SignedIn.svelte Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to prevent dashboard skeleton UI from rendering during SSR by ensuring deferred content can resolve against real page props, and by adjusting the Home/SignedIn dashboard rendering logic.

Changes:

  • Pre-populate Inertia’s global page store before the initial render in the Svelte adapter App.svelte to support SSR resolution for Deferred/WhenVisible.
  • Update Home/SignedIn.svelte to render dashboard content immediately when dashboard_stats is already present, otherwise fall back to <Deferred> with skeletons.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 2 comments.

File Description
vendor/inertia/packages/svelte/dist/components/App.svelte Sets the global page store earlier to affect SSR behavior for deferred content.
app/javascript/pages/Home/SignedIn.svelte Avoids skeleton rendering when dashboard_stats is present by bypassing <Deferred> in that case.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/javascript/pages/Home/SignedIn.svelte Outdated
Comment thread app/javascript/pages/Home/SignedIn.svelte Outdated
@skyfallwastaken skyfallwastaken merged commit 0943e11 into main Apr 20, 2026
14 checks passed
@skyfallwastaken skyfallwastaken deleted the ssr-deferred branch April 20, 2026 09:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants